package com.journeyapps.barcodescanner;

import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.google.zxing.DecodeHintType;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.DecodeHintManager;
import com.google.zxing.client.android.Intents;
import com.google.zxing.client.android.R;
import com.journeyapps.barcodescanner.camera.CameraParametersCallback;
import com.journeyapps.barcodescanner.camera.CameraSettings;

import java.util.List;
import java.util.Map;

import me.zhouzhuo810.magpiex.ui.widget.TitleBar;

/**
 * Encapsulates BarcodeView, ViewfinderView and status text.
 *
 * To customize the UI, use BarcodeView and ViewfinderView directly.
 */
public class DecoratedBarcodeView extends FrameLayout {
    private BarcodeView barcodeView;
    private ViewfinderView viewFinder;
    private TextView statusView;
    private TitleBar mTitleBar;
    
    /**
     * The instance of @link TorchListener to send events callback.
     */
    private TorchListener torchListener;
    
    private class WrappedCallback implements BarcodeCallback {
        private BarcodeCallback delegate;
        
        public WrappedCallback(BarcodeCallback delegate) {
            this.delegate = delegate;
        }
        
        @Override
        public void barcodeResult(BarcodeResult result) {
            delegate.barcodeResult(result);
        }
        
        @Override
        public void possibleResultPoints(List<ResultPoint> resultPoints) {
            for (ResultPoint point : resultPoints) {
                viewFinder.addPossibleResultPoint(point);
            }
            delegate.possibleResultPoints(resultPoints);
        }
    }
    
    public DecoratedBarcodeView(Context context) {
        super(context);
        initialize();
    }
    
    public DecoratedBarcodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize(attrs);
    }
    
    public DecoratedBarcodeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize(attrs);
    }
    
    /**
     * Initialize the view with the xml configuration based on styleable attributes.
     *
     * @param attrs The attributes to use on view.
     */
    private void initialize(AttributeSet attrs) {
        // Get attributes set on view
        TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.zxing_view);
        
        int scannerLayout = attributes.getResourceId(
            R.styleable.zxing_view_zxing_scanner_layout, R.layout.zxing_barcode_scanner);
        
        attributes.recycle();
        
        inflate(getContext(), scannerLayout, this);
        
        
        mTitleBar = (TitleBar) findViewById(R.id.title_bar);
        
        barcodeView = (BarcodeView) findViewById(R.id.zxing_barcode_surface);
        
        if (barcodeView == null) {
            throw new IllegalArgumentException(
                "There is no a com.journeyapps.barcodescanner.BarcodeView on provided layout " +
                    "with the id \"zxing_barcode_surface\".");
        }
        
        // Pass on any preview-related attributes
        barcodeView.initializeAttributes(attrs);
        
        
        viewFinder = (ViewfinderView) findViewById(R.id.zxing_viewfinder_view);
        
        if (viewFinder == null) {
            throw new IllegalArgumentException(
                "There is no a com.journeyapps.barcodescanner.ViewfinderView on provided layout " +
                    "with the id \"zxing_viewfinder_view\".");
        }
        
        viewFinder.setCameraPreview(barcodeView);
        
        // statusView is optional
        statusView = (TextView) findViewById(R.id.zxing_status_view);
    }
    
    /**
     * Initialize with no custom attributes setted.
     */
    private void initialize() {
        initialize(null);
    }
    
    /**
     * Convenience method to initialize camera id, decode formats and prompt message from an intent.
     *
     * @param intent the intent, as generated by IntentIntegrator
     */
    public void initializeFromIntent(Intent intent) {
        // Scan the formats the intent requested, and return the result to the calling activity.
        Map<DecodeHintType, Object> decodeHints = DecodeHintManager.parseDecodeHints(intent);
        
        CameraSettings settings = new CameraSettings();
        
        if (intent.hasExtra(Intents.Scan.CAMERA_ID)) {
            int cameraId = intent.getIntExtra(Intents.Scan.CAMERA_ID, -1);
            if (cameraId >= 0) {
                settings.setRequestedCameraId(cameraId);
            }
        }
        
        String customPromptMessage = intent.getStringExtra(Intents.Scan.PROMPT_MESSAGE);
        if (customPromptMessage != null) {
            setStatusText(customPromptMessage);
        }
        
        String title = intent.getStringExtra(Intents.Scan.CUSTOM_TITLE_TEXT);
        if (title != null) {
            setTitleText(title);
        }
        
        int titleBg = intent.getIntExtra(Intents.Scan.CUSTOM_TITLE_BG, -1);
        if (titleBg != -1) {
            setTitleBg(titleBg);
        }
        
        int titleTextColor = intent.getIntExtra(Intents.Scan.CUSTOM_TEXT_COLOR, Color.WHITE);
        setTitleTextColor(titleTextColor);
        
        boolean enableAlbum = intent.getBooleanExtra(Intents.Scan.ALBUM_ENABLE, true);
        setAlbumEnabled(enableAlbum);
        
        // Check what type of scan. Default: normal scan
        int scanType = intent.getIntExtra(Intents.Scan.SCAN_TYPE, 0);
        String characterSet = intent.getStringExtra(Intents.Scan.CHARACTER_SET);
        barcodeView.setCameraSettings(settings);
        barcodeView.setDecoderFactory(new DefaultDecoderFactory(decodeHints, characterSet, scanType));
    }
    
    private void setTitleBg(int titleBg) {
        if (mTitleBar != null) {
            mTitleBar.setBackgroundResource(titleBg);
        }
    }
    
    private void setTitleTextColor(int titleTextColor) {
        if (mTitleBar != null) {
            mTitleBar.getTvLeft().setTextColor(titleTextColor);
            mTitleBar.getTvTitle().setTextColor(titleTextColor);
            mTitleBar.getTvRight().setTextColor(titleTextColor);
        }
    }
    
    private void setAlbumEnabled(boolean enableAlbum) {
        if (mTitleBar != null) {
            mTitleBar.getLlRight().setVisibility(enableAlbum ? VISIBLE : GONE);
        }
    }
    
    public TitleBar getTitleBar() {
        return mTitleBar;
    }
    
    /**
     * 设置标题
     */
    public void setTitleText(String title) {
        if (mTitleBar != null) {
            mTitleBar.getTvTitle().setText(title);
        }
    }
    
    public void setStatusText(String text) {
        // statusView is optional when using a custom layout
        if (statusView != null) {
            statusView.setText(text);
        }
        if (viewFinder != null) {
            viewFinder.setHintText(text);
        }
    }
    
    /**
     * @see BarcodeView#pause()
     */
    public void pause() {
        barcodeView.pause();
    }
    
    /**
     * @see BarcodeView#pauseAndWait()
     */
    public void pauseAndWait() {
        barcodeView.pauseAndWait();
    }
    
    /**
     * @see BarcodeView#resume()
     */
    public void resume() {
        barcodeView.resume();
    }
    
    public BarcodeView getBarcodeView() {
        return (BarcodeView) findViewById(R.id.zxing_barcode_surface);
    }
    
    public ViewfinderView getViewFinder() {
        return viewFinder;
    }
    
    public TextView getStatusView() {
        return statusView;
    }
    
    /**
     * @see BarcodeView#decodeSingle(BarcodeCallback)
     */
    public void decodeSingle(BarcodeCallback callback) {
        barcodeView.decodeSingle(new WrappedCallback(callback));
    }
    
    /**
     * @see BarcodeView#decodeContinuous(BarcodeCallback)
     */
    public void decodeContinuous(BarcodeCallback callback) {
        barcodeView.decodeContinuous(new WrappedCallback(callback));
    }
    
    /**
     * Turn on the device's flashlight.
     */
    public void setTorchOn() {
        barcodeView.setTorch(true);
        
        if (torchListener != null) {
            torchListener.onTorchOn();
        }
    }
    
    /**
     * Turn off the device's flashlight.
     */
    public void setTorchOff() {
        barcodeView.setTorch(false);
        
        if (torchListener != null) {
            torchListener.onTorchOff();
        }
    }
    
    /**
     * Changes the settings for Camera.
     * Must be called after {@link #resume()}.
     *
     * @param callback {@link CameraParametersCallback}
     */
    public void changeCameraParameters(CameraParametersCallback callback) {
        barcodeView.changeCameraParameters(callback);
    }
    
    /**
     * Handles focus, camera, volume up and volume down keys.
     *
     * Note that this view is not usually focused, so the Activity should call this directly.
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_FOCUS:
            case KeyEvent.KEYCODE_CAMERA:
                // Handle these events so they don't launch the Camera app
                return true;
            // Use volume up/down to turn on light
            case KeyEvent.KEYCODE_VOLUME_DOWN:
                setTorchOff();
                return true;
            case KeyEvent.KEYCODE_VOLUME_UP:
                setTorchOn();
                return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    
    public void setTorchListener(TorchListener listener) {
        this.torchListener = listener;
    }
    
    /**
     * The Listener to torch/fflashlight events (turn on, turn off).
     */
    public interface TorchListener {
        
        void onTorchOn();
        
        void onTorchOff();
    }
}
